import pandas as pd
from quant_researcher.quant.project_tool.time_tool import datetime_to_timestamp, timestamp_to_str, timestamp_to_datetime
import requests, json
import os
import datetime
import hashlib
import urllib.parse
import hmac


API_KEY = "oMlYVBgANplqH7XilK0rzJ47r7p1R3MWoywVNBYOGvj5UHYXebQnxZjX9kLpdd5V"
SECRET_KEY = "8587vRjV45QsPPXhlrn3vcBdUwQJFA6HIBqfaVbJO7UqhhqTcVrQCR4GEO6w4OtN"


def generate_signature(params, secret_key):
    query_string = urllib.parse.urlencode(params)
    signature = hmac.new(secret_key.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256).hexdigest()
    return signature


def get_binance_server_time():
    """获取币安服务器时间"""
    url = 'https://api.binance.com/api/v3/time'
    response = requests.get(url)
    if response.status_code == 200:
        return response.json()['serverTime']
    else:
        raise Exception("无法获取币安服务器时间")



def fetch_binance_margin_interest_rate(asset, start_time, end_time, callback_func=None):
    """
    https://www.binance.com/en/margin/interest-history

    Get the latest symbol‘s funding_rate data
    时间倒序切片获取算法，是各大交易所获取1min数据的神器，因为大部分交易所直接请求跨月跨年的1min分钟数据
    会直接返回空值，只有将 start_epoch，end_epoch 切片细分到 200/300 bar 以内，才能正确返回 kline，
    火币和binance，OKEx 均为如此，直接用跨年时间去直接请求上万bar 的 kline 数据永远只返回最近200条数据。
    """

    def format_funding_rate_data(datas, symbol, frequency):
        """
        # 归一化数据字段，转换填充必须字段，删除多余字段
        参数名 	类型 	描述
        time 	String 	开始时间
        open 	String 	开盘价格
        high 	String 	最高价格
        low 	String 	最低价格
        close 	String 	收盘价格
        volume 	String 	交易量
        """

        return frame

    shift_gap = 25 * 24 * 60 * 60

    datas = list()
    reqParams = {}
    reqParams['from'] = end_time - shift_gap
    if reqParams['from'] < start_time:
        reqParams['from'] = start_time
    reqParams['to'] = end_time

    while (reqParams['to'] > start_time):
        if ((reqParams['from'] > datetime_to_timestamp())) or ((reqParams['from'] > reqParams['to'])):
            # 出现“未来”时间，一般是默认时区设置，或者时间窗口滚动前移错误造成的
            print(
                'A unexpected \'Future\' timestamp got, Please check self.missing_data_list_func param \'tzlocalize\' set. More info: {:s}@{:s} at {:s} but current time is {}'
                    .format(
                    asset,
                    timestamp_to_str(reqParams['from']),
                    timestamp_to_str(datetime_to_timestamp())
                )
            )
            # 跳到下一个时间段
            reqParams['to'] = int(reqParams['from'] - 1)
            reqParams['from'] = int(reqParams['from'] - shift_gap)
            if reqParams['from'] < start_time:
                reqParams['from'] = start_time
            continue

        # url = 'https://www.binance.com/bapi/margin/v1/public/margin/vip/spec/history-interest-rate'
        base_url = 'https://api.binance.com'
        endpoint = '/sapi/v1/margin/interestRateHistory'
        url = base_url + endpoint

        params = {
            "asset": asset,
            "vipLevel": 0,
            "size": 90,
            "startTime": int(reqParams['from'] * 1000),
            "endTime": int(reqParams['to'] * 1000),
        'timestamp':  get_binance_server_time(),
        'recvWindow': 50000  # 设置接收窗口为5秒
        }
        print(f"开始获取{timestamp_to_str(reqParams['from'])} - {timestamp_to_str(reqParams['to'])}的数据")
        # 准备请求头
        headers = {
            'X-MBX-APIKEY': API_KEY
        }
        # 生成签名
        signature = generate_signature(params, SECRET_KEY)
        params['signature'] = signature

        req = requests.get(url=url, params=params, headers=headers)
        margin_interest_rate = json.loads(req.content)


        reqParams['to'] = int(reqParams['from'] - 1)
        reqParams['from'] = int(reqParams['from'] - shift_gap)
        if reqParams['from'] < start_time:
            reqParams['from'] = start_time


        datas.extend(margin_interest_rate)

        if (callback_func is not None):
            frame = format_funding_rate_data(margin_interest_rate)

    if len(datas) == 0:
        return None

    frame = pd.DataFrame(datas)
    frame['dailyInterestRate'] = frame['dailyInterestRate'].astype(float)
    frame['dailyInterestRate'] = frame['dailyInterestRate'] * 365  # 年化，并转为%
    frame.rename({'dailyInterestRate': 'margin_interest_rate'}, axis=1, inplace=True)
    frame.sort_values(by='timestamp', inplace=True)
    frame['timestamp'] = frame['timestamp'].astype(float)

    frame.drop_duplicates(subset=['timestamp'], keep='first', inplace=True)

    return frame


start = datetime.datetime(2025, 8, 1, 0, 0, 0, tzinfo=datetime.timezone.utc).timestamp()
end = datetime.datetime(2025, 8, 29, 0, 0, 0, tzinfo=datetime.timezone.utc).timestamp()
# 测试fetch_binance_margin_interest_rate
for asset in ['USDT', 'BTC', 'ETH']:
    frame = fetch_binance_margin_interest_rate(asset=asset, start_time=start, end_time=end)
    frame['start_time'] = frame.apply(lambda x: int(x['timestamp'] / 1000), axis=1)
    frame['date'] = pd.to_datetime(frame['start_time'], unit='s').dt.tz_localize('UTC').dt.tz_convert('Asia/Shanghai')
    frame['date'] = frame['date'].dt.strftime('%Y-%m-%d')
    frame['datetime'] = pd.to_datetime(frame['start_time'], unit='s').dt.tz_localize('UTC').dt.tz_convert('Asia/Shanghai')
    frame['datetime'] = frame['datetime'].dt.strftime('%Y-%m-%d %H:%M:%S')
    frame.set_index('date', inplace=True)
    file_path = os.path.join("G:/", f'margin_interest_rate')
    os.makedirs(file_path, exist_ok=True)
    file_name = os.path.join(file_path, f'binance_{asset}_margin_interest_rate')
    frame.to_excel(f'{file_name}.xlsx')